`timescale 1ns/100ps

`include "sim_glb.sv"

module tc;

localparam          CLK_PRD                 = 6.0;

reg                                         rst_n;
reg                                         clk;


wire        signed  [12-1:0]                lpsg_dat;
reg         signed  [12-1:0]                lpsg_dat_1d;
wire        signed  [12-1:0]                ref_dat;

reg                                         fifo_wen;
wire                                        fifo_empty;
wire                                        mem_wen;
wire                [5-1:0]                 mem_waddr;
wire                [24-1:0]                mem_wdata;
wire                                        mem_ren;
wire                [5-1:0]                 mem_raddr;
wire                [7-1:0]                 coe_ram_radr;
wire                                        coe_ram_ren;
reg                 [10*14-1:0]             coe_ram_rdat;   // {CN, ...... , C1, C0}, C0 is for latest data
wire                                        smp_fifo_ren;
wire                [2*12-1:0]              smp_fifo_rdat;  // {smp1, smp0}, smp1 is later than smp0

wire        signed  [16-1:0]                gain;
wire        signed  [12-1:0]                fdf_dat;
wire        signed  [28-1:0]                gain_dat_c;
wire        signed  [12-1:0]                gain_dat;

initial begin:CRG
    rst_n=1'b0;
    clk=1'b1;

    fork
        rst_n=#100.5 1'b1;
        forever clk=#CLK_PRD ~clk;
    join
end

RGRS_MNG    rgrs;
initial begin:REGRESS
    rgrs = new("tc_ssr_fdf", 1);

    rgrs.wait_chks_done(100_000_000);
end

lpsg_prbs #(      // low-pass signal generator by means of PRBS
        .LPSG_DW                        (12                             ),
        .LVL_BW                         (4                              ),
        .PRBS_N                         (23                             ),
        .EMA_K_MAX                      (15                             ),	// Maximum of cfg_ema_k
        .EMA_K_MIN                      (2                              ),	// Minimum of cfg_ema_k
        .GAIN_DW                        (8                              ),	// total bit-width
        .GAIN_FW                        (5                              ) 	// fractional bit-width
) u_lpsg_prbs ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),
        .cke                            (1'b1                           ),

        .lpsg_dat                       (lpsg_dat                       ),

        .cfg_ema_k                      (4'd3                           ),
        .cfg_gain                       (8'b001_00000                   )	// u(GAIN_DW, GAIN_FW)
);

wire        signed  [12-1:0]                dly_dat;

dly_mem #(
        .DW                             (12                             ),
        .DEPTH                          (32                             ),
        .MEM_STYLE                      ("TINY_MEM"                     ),	// "TPRAM"
        .EARLY_DATA                     ("ZERO"                         ),	// "ZERO"
        .ECC_MODE                       ("NONE"                         ) 	// no ECC
) u_dly_mem ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),
        .cke                            (1'b1                           ),

        .id                             (lpsg_dat                       ),	// data before delay
        .od                             (dly_dat                        ),	// actual delay is (cfg_dly+2)*cke + (mem_rd_latency-1)

        .cfg_dly                        (5'd20                          )
);

wire                [10*14-1:0]             coe_fix;

//fir_pp #(
//        .CDW                            (14                             ),
//        .CFW                            (13                             ),
//        .IDW                            (12                             ),
//        .IFW                            (9                              ),
//        .ODW                            (12                             ),
//        .OFW                            (9                              ),
//        .TAP_NUM                        (10                             ),	// must TAP_NUM>=2
//        .COPY_NUM                       (1                              ),	// COPY_NUM>=1, the number of in_dat copy for fan-out
//        .VLD_USE                        (1'b1                           ),
//        .IN_REG_EN                      (1'b1                           ),
//        .P_REG_EN                       (1'b1                           )
//) u_fir_pp ( 
//        .rst_n                          (rst_n                          ),
//        .clk                            (clk                            ),
//
//        .in_vld                         (1'b1                           ),
//        .in_coe                         (coe_fix                        ),	// {CN-1, .... C1, C0}
//        .in_dat                         (dly_dat                        ),
//
//        .out_vld                        (                               ),
//        .out_dat                        (ref_dat                        )
//);

wire        signed  [28-1:0]                ref_dat_c;
assign ref_dat_c = dly_dat*$signed(16'd15617);

s_sat_tru #(     // range [-(2^(IDW-1))/(2^IFW):(2^(IDW-1)-1)/(2^IFW)]
        .IDW                            (12+16                          ),	// input data width, (IDW-IFW)>=(ODW-OFW)
        .IFW                            (9+14                           ),	// input fractional width,  IFW>=IDW is legal
        .ODW                            (12                             ),	// output data width
        .OFW                            (9                              )	// output fractional width, OFW>=ODW is legal
) u_ref_dat_tru ( 
        .id                             (ref_dat_c                      ),	// s(IDW, IFW), the MSB is sign
        .od                             (ref_dat                        ),	// s(ODW, OFW), the MSB is sign
        .over                           (                               )
);

always@(posedge clk or negedge rst_n) begin
    if (rst_n==1'b0) begin
        fifo_wen <=`U_DLY 1'b0;
        lpsg_dat_1d <=`U_DLY 12'd0;
    end else begin
        fifo_wen <=`U_DLY ~fifo_wen;
        if (fifo_wen==1'b0) begin
            lpsg_dat_1d <=`U_DLY lpsg_dat;
        end
    end
end

assign mem_wdata = {lpsg_dat, lpsg_dat_1d};
sfifo_ctrl #(
        .DEPTH                          (32                             ) 	// must DEPTH>=2
) u_smp_fifo ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),

        .fifo_wen                       (fifo_wen                       ),
        .fifo_full                      (                               ),
        .fifo_afull                     (                               ),	// afull

        .fifo_ren                       (smp_fifo_ren                   ),
        .fifo_empty                     (fifo_empty                     ),
        .fifo_aempty                    (                               ),	// aempty

        .fifo_cnt                       (                               ),

        .mem_wen                        (mem_wen                        ),
        .mem_waddr                      (mem_waddr                      ),
        .mem_ren                        (mem_ren                        ),
        .mem_raddr                      (mem_raddr                      ),

        .cfg_fifo_afull_th              (5'd30                          ),	// afull_th<fifo_cnt<, range is [0:DEPTH-1]
        .cfg_fifo_aempty_th             (5'd1                           ),	// 0<, range is [1:min(DEPTH,2^ADDR_BW-1)]
        .err_fifo_ilf                   (                               ),	// fifo internal logic fault
        .err_fifo_wof                   (                               ),	// fifo write overflow
        .err_fifo_ruf                   (                               )	// fifo read underflow
);

// two-port RAM
tpram_wrap #(
        .DEPTH                          (32                             ),
        .DATA_BW                        (2*12                           ),
        .RDPL_NUM                       (1                              ),	// Read Data Pipe Line number
        .USER_DEF_TAG                   ("NONE"                         ),
        .ECC_MODE                       ("NONE"                         ) 	// no ECC
) u_smp_ram ( 
        .rst_wr_n                       (rst_n                          ),
        .clk_wr                         (clk                            ),
        .mem_wen                        (mem_wen                        ),
        .mem_waddr                      (mem_waddr                      ),
        .mem_wdata                      (mem_wdata                      ),

        .cfg_frc_sbe                    (1'b0                           ),	// support at ECC_MODE

        .rst_rd_n                       (rst_n                          ),
        .clk_rd                         (clk                            ),
        .mem_ren                        (mem_ren                        ),
        .mem_rdpl_ce                    ({1{1'b1}}                      ),
        .mem_raddr                      (mem_raddr                      ),
        .mem_rvld                       (                               ),
        .mem_rdata                      (smp_fifo_rdat                  ),

        .alm_ecc_err                    (                               ),	// support at ECC_MODE
        .alm_ecc_dbe                    (                               )	// support at ECC_MODE
);

localparam          NCO_FW                  = 28;

wire                                        ref_vld;
wire                                        fdf_vld;
wire                [NCO_FW:0]              freq_word;

assign ref_vld = ~fifo_empty;

ssr_fdf #(
        .PHS_FW                         (7                              ),
        .NCO_FW                         (NCO_FW                         ),	// must NCO_FW >= PHS_FW
        .RDPL                           (1                              ),	// RAM read pipeline
        .CDW                            (14                             ),	// coefficient data width
        .CFW                            (13                             ),	// coefficient fractional width
        .IDW                            (12                             ),	// input data width
        .IFW                            (9                              ),	// input fractional width
        .ODW                            (12                             ),	// output data width
        .OFW                            (9                              ),	// output fractional width
        .COE_NUM                        (10                             ),	// COE_NUM>=1
        .IN_REG_EN                      (1'b0                           ),
        .CSCD_LEN_MAX                   (5                              ),	// CSCD_LEN_MAX>=2, cascade length, if too bigger, bad Fmax
        .LVL_REG                        (1'b1                           ) 	// specify register for each level
) u_ssr_fdf ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),

        .ref_vld                        (ref_vld                        ),	// reference valid for sample rate
        .freq_word                      (freq_word                      ),	// freq_word is more of less than (2^NCO_FW)

        .coe_ram_radr                   (coe_ram_radr                   ),
        .coe_ram_ren                    (coe_ram_ren                    ),
        .coe_ram_rdat                   (coe_ram_rdat                   ),	// {CN, ...... , C1, C0}, C0 is for latest data

        .smp_fifo_ren                   (smp_fifo_ren                   ),
        .smp_fifo_rdat                  (smp_fifo_rdat                  ),	// {smp1, smp0}, smp1 is later than smp0

        .out_vld                        (fdf_vld                        ),
        .out_dat                        (fdf_dat                        )
);

assign gain_dat_c = fdf_dat*gain;

s_sat_tru #(     // range [-(2^(IDW-1))/(2^IFW):(2^(IDW-1)-1)/(2^IFW)]
        .IDW                            (28                             ),	// input data width, (IDW-IFW)>=(ODW-OFW)
        .IFW                            (9+14                           ),	// input fractional width,  IFW>=IDW is legal
        .ODW                            (12                             ),	// output data width
        .OFW                            (9                              )	// output fractional width, OFW>=ODW is legal
) u_gain_dat_tru ( 
        .id                             (gain_dat_c                     ),	// s(IDW, IFW), the MSB is sign
        .od                             (gain_dat                       ),	// s(ODW, OFW), the MSB is sign
        .over                           (                               )
);

reg         signed  [12-1:0]                ref_dat_1d;
reg         signed  [12-1:0]                ref_dat_2d;
wire        signed  [26-1:0]                err;

always@(posedge clk or negedge rst_n) begin
    if (rst_n==1'b0) begin
        ref_dat_1d <=`U_DLY 12'd0;
        ref_dat_2d <=`U_DLY 12'd0;
    end else begin
        ref_dat_1d <=`U_DLY ref_dat;
        ref_dat_2d <=`U_DLY ref_dat_1d;
    end
end

assign err = (ref_dat - ref_dat_2d)*(ref_dat_1d - gain_dat);

wire        signed  [21-1:0]                ctrl;

pi_ctrl #(    // proportional and integral accumulator 
        .IN_DW                          (26                             ),
        .IN_FW                          (18                             ),
        .OUT_FW                         (28                             ),	// must OUT_FW<=IN_FW+KI_MAX
        .PINC_DW                        (20                             ),	// must PINC_DW<=OUT_FW+IN_DW-IN_FW-KP_MIN
        .IINC_DW                        (15                             ),
        .IACC_FW                        (38                             ),	// must OUT_FW<=IACC_FW<=IN_FW+KI_MAX
        .KP_MAX                         (12                             ),
        .KP_MIN                         (4                              ),
        .KI_MAX                         (24                             ),	// must KI_MAX>=KP_MAX
        .KI_MIN                         (16                             )
) u_pi_ctrl ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),
        .cke                            (1'b1                           ),

        .in_vld                         (fdf_vld                        ),
        .in_dat                         (err                            ),	// s(  IN_DW,   IN_FW)
        .out_vld                        (                               ),
        .out_dat                        (ctrl                           ),	// s( OUT_DW,  OUT_FW)

        .cfg_kp                         (4'd6                           ),	// range [KP_MIN:KP_MAX], gain 
        .cfg_ki                         (5'd10                          ),	// range [KI_MIN:KI_MAX], gain 

        .cfg_acc_clr                    (1'b0                           ),
        .cfg_acc_frz                    (1'b0                           ),
        .cfg_acc_ini                    (15'd0                          ),	// s(IINC_DW, IINC_FW), initial value
        .sts_acc_rtv                    (                               )	// s(IINC_DW, IINC_FW), real-time value
);

assign freq_word = {{NCO_FW+1-21{ctrl[20]}}, ctrl} + (1'b1<<NCO_FW);

wire        signed  [13-1:0]                gain_err;

assign gain_err = (ref_dat_1d>=0) ? ref_dat_1d - gain_dat : 
                                    gain_dat - ref_dat_1d;

p_acc #(   //proportional accumulator 
        .IN_DW                          (13                             ),
        .IN_FW                          (9                              ),
        .OUT_DW                         (16                             ),
        .OUT_FW                         (14                             ),	// must OUT_FW<=ACC_FW
        .ACC_FW                         (24                             ),	// must ACC_FW<=IN_FW+K_MAX
        .K_MAX                          (15                             ),	// must K_MAX>=K_MIN
        .K_MIN                          (8                              )
) u_p_acc ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),
        .cke                            (1'b1                           ),

        .in_vld                         (fdf_vld                        ),
        .in_dat                         (gain_err                       ),	// s( IN_DW,  IN_FW)
        .out_dat                        (gain                           ),	// s(OUT_DW, OUT_FW), convert it to unsinged by flop the highest bit

        .cfg_k                          (4'd10                          ),	// range [K_MIN:K_MAX], gain 

        .cfg_acc_clr                    (1'b0                           ),	// clear acc to cfg_ini
        .cfg_acc_frz                    (1'b0                           ),	// freeze acc, but cfg_frz is lower priority than cfg_clr
        .cfg_acc_ini                    (                               ),	// s(OUT_DW, OUT_FW), initial value
        .sts_acc_rtv                    (                               )	// s(OUT_DW, OUT_FW), real-time value
);

initial begin:CHK_
    integer cnt_time;

    cnt_time=0;
    @(posedge rst_n);

    #500_000;
    while(cnt_time<10000) begin
        @(posedge clk);
        if (gain_err>4 || gain_err<-4) begin
            cnt_time = 0;
        end else begin
            cnt_time = cnt_time + 1;
        end
    end

    rgrs.one_chk_done("chk num is done.");
end


wire                [14*10-1:0]             coe_ary[127:0];

always @(posedge clk) begin
	if(coe_ram_ren) begin
        coe_ram_rdat <= coe_ary[coe_ram_radr];
	end
end

assign coe_fix = coe_ary[0];

reg         signed  [14-1:0]                coe_wave;
reg         signed  [16-1:0]                coe_sum;

initial begin:WAVE
    integer i,j;

    i=0;
    j=0;
    coe_wave = 0;
    @(posedge rst_n)
    @(posedge clk);

    for (j=0; j<128; j=j+1) begin
        coe_sum = 0;
        for (i=0; i<10; i=i+1) begin
            coe_wave = coe_ary[j][i*14+:14];
            coe_sum = coe_sum + coe_wave;
        end
        $display("Phase %3d:sum is %d", j, coe_sum);
    end

    @(posedge clk);
    
    for (i=0; i<10; i=i+1) begin
        for (j=0; j<128; j=j+1) begin
            coe_wave = coe_ary[j][i*14+:14];
            @(posedge clk);
        end
    end
    coe_wave = 0;
end


assign coe_ary[7'd000] = {14'h2f  , 14'h3f7d, 14'hf6  , 14'h3e98, 14'h1fee, 14'h3ecd, 14'he5  , 14'h3f82, 14'h2f  , 14'h3ff7};
assign coe_ary[7'd001] = {14'h30  , 14'h3f78, 14'h107 , 14'h3e64, 14'h1fec, 14'h3f03, 14'hd4  , 14'h3f87, 14'h2e  , 14'h3ff7};
assign coe_ary[7'd002] = {14'h30  , 14'h3f74, 14'h117 , 14'h3e32, 14'h1fe8, 14'h3f3b, 14'hc2  , 14'h3f8c, 14'h2d  , 14'h3ff7};
assign coe_ary[7'd003] = {14'h31  , 14'h3f70, 14'h126 , 14'h3e01, 14'h1fe2, 14'h3f73, 14'hb0  , 14'h3f91, 14'h2d  , 14'h3ff7};
assign coe_ary[7'd004] = {14'h31  , 14'h3f6c, 14'h135 , 14'h3dd1, 14'h1fdb, 14'h3fad, 14'h9d  , 14'h3f97, 14'h2c  , 14'h3ff7};
assign coe_ary[7'd005] = {14'h31  , 14'h3f68, 14'h144 , 14'h3da2, 14'h1fd1, 14'h3fe8, 14'h8a  , 14'h3f9c, 14'h2b  , 14'h3ff7};
assign coe_ary[7'd006] = {14'h32  , 14'h3f64, 14'h152 , 14'h3d75, 14'h1fc6, 14'h25  , 14'h77  , 14'h3fa2, 14'h2a  , 14'h3ff7};
assign coe_ary[7'd007] = {14'h32  , 14'h3f61, 14'h160 , 14'h3d49, 14'h1fb8, 14'h62  , 14'h63  , 14'h3fa8, 14'h29  , 14'h3ff6};
assign coe_ary[7'd008] = {14'h32  , 14'h3f5e, 14'h16d , 14'h3d1f, 14'h1fa9, 14'ha1  , 14'h4f  , 14'h3fae, 14'h28  , 14'h3ff6};
assign coe_ary[7'd009] = {14'h32  , 14'h3f5b, 14'h17a , 14'h3cf5, 14'h1f98, 14'he1  , 14'h3a  , 14'h3fb5, 14'h27  , 14'h3ff6};
assign coe_ary[7'd010] = {14'h32  , 14'h3f58, 14'h186 , 14'h3ccd, 14'h1f85, 14'h122 , 14'h25  , 14'h3fbb, 14'h25  , 14'h3ff6};
assign coe_ary[7'd011] = {14'h32  , 14'h3f55, 14'h192 , 14'h3ca7, 14'h1f70, 14'h164 , 14'h10  , 14'h3fc2, 14'h24  , 14'h3ff6};
assign coe_ary[7'd012] = {14'h32  , 14'h3f53, 14'h19d , 14'h3c81, 14'h1f59, 14'h1a7 , 14'h3ffa, 14'h3fc9, 14'h23  , 14'h3ff6};
assign coe_ary[7'd013] = {14'h32  , 14'h3f51, 14'h1a8 , 14'h3c5d, 14'h1f40, 14'h1eb , 14'h3fe4, 14'h3fd0, 14'h21  , 14'h3ff6};
assign coe_ary[7'd014] = {14'h32  , 14'h3f4e, 14'h1b2 , 14'h3c3a, 14'h1f26, 14'h231 , 14'h3fce, 14'h3fd7, 14'h20  , 14'h3ff6};
assign coe_ary[7'd015] = {14'h32  , 14'h3f4d, 14'h1bc , 14'h3c19, 14'h1f0a, 14'h277 , 14'h3fb8, 14'h3fdf, 14'h1e  , 14'h3ff6};
assign coe_ary[7'd016] = {14'h31  , 14'h3f4b, 14'h1c6 , 14'h3bf9, 14'h1eec, 14'h2bf , 14'h3fa1, 14'h3fe6, 14'h1c  , 14'h3ff6};
assign coe_ary[7'd017] = {14'h31  , 14'h3f49, 14'h1cf , 14'h3bda, 14'h1ecc, 14'h307 , 14'h3f89, 14'h3fee, 14'h1b  , 14'h3ff6};
assign coe_ary[7'd018] = {14'h31  , 14'h3f48, 14'h1d7 , 14'h3bbc, 14'h1eaa, 14'h351 , 14'h3f72, 14'h3ff6, 14'h19  , 14'h3ff6};
assign coe_ary[7'd019] = {14'h30  , 14'h3f47, 14'h1df , 14'h3ba0, 14'h1e86, 14'h39c , 14'h3f5a, 14'h3ffe, 14'h17  , 14'h3ff6};
assign coe_ary[7'd020] = {14'h30  , 14'h3f46, 14'h1e6 , 14'h3b85, 14'h1e61, 14'h3e7 , 14'h3f42, 14'h6   , 14'h15  , 14'h3ff6};
assign coe_ary[7'd021] = {14'h2f  , 14'h3f45, 14'h1ed , 14'h3b6b, 14'h1e3a, 14'h434 , 14'h3f2a, 14'hf   , 14'h13  , 14'h3ff6};
assign coe_ary[7'd022] = {14'h2f  , 14'h3f44, 14'h1f4 , 14'h3b53, 14'h1e12, 14'h481 , 14'h3f11, 14'h17  , 14'h11  , 14'h3ff7};
assign coe_ary[7'd023] = {14'h2e  , 14'h3f43, 14'h1fa , 14'h3b3c, 14'h1de7, 14'h4cf , 14'h3ef9, 14'h20  , 14'hf   , 14'h3ff7};
assign coe_ary[7'd024] = {14'h2e  , 14'h3f43, 14'h200 , 14'h3b26, 14'h1dbb, 14'h51e , 14'h3ee0, 14'h28  , 14'hd   , 14'h3ff7};
assign coe_ary[7'd025] = {14'h2d  , 14'h3f43, 14'h205 , 14'h3b11, 14'h1d8d, 14'h56e , 14'h3ec7, 14'h31  , 14'hb   , 14'h3ff7};
assign coe_ary[7'd026] = {14'h2d  , 14'h3f43, 14'h209 , 14'h3afe, 14'h1d5e, 14'h5bf , 14'h3ead, 14'h3a  , 14'h8   , 14'h3ff7};
assign coe_ary[7'd027] = {14'h2c  , 14'h3f43, 14'h20e , 14'h3aec, 14'h1d2d, 14'h611 , 14'h3e94, 14'h43  , 14'h6   , 14'h3ff7};
assign coe_ary[7'd028] = {14'h2b  , 14'h3f43, 14'h211 , 14'h3adb, 14'h1cfa, 14'h663 , 14'h3e7b, 14'h4d  , 14'h4   , 14'h3ff8};
assign coe_ary[7'd029] = {14'h2b  , 14'h3f44, 14'h215 , 14'h3acc, 14'h1cc6, 14'h6b6 , 14'h3e61, 14'h56  , 14'h1   , 14'h3ff8};
assign coe_ary[7'd030] = {14'h2a  , 14'h3f44, 14'h217 , 14'h3abd, 14'h1c91, 14'h70a , 14'h3e47, 14'h5f  , 14'h3ffe, 14'h3ff8};
assign coe_ary[7'd031] = {14'h29  , 14'h3f45, 14'h21a , 14'h3ab0, 14'h1c59, 14'h75f , 14'h3e2d, 14'h69  , 14'h3ffc, 14'h3ff8};
assign coe_ary[7'd032] = {14'h28  , 14'h3f46, 14'h21c , 14'h3aa4, 14'h1c21, 14'h7b4 , 14'h3e14, 14'h72  , 14'h3ff9, 14'h3ff9};
assign coe_ary[7'd033] = {14'h28  , 14'h3f47, 14'h21d , 14'h3a99, 14'h1be6, 14'h80a , 14'h3dfa, 14'h7c  , 14'h3ff7, 14'h3ff9};
assign coe_ary[7'd034] = {14'h27  , 14'h3f48, 14'h21e , 14'h3a8f, 14'h1bab, 14'h860 , 14'h3de0, 14'h86  , 14'h3ff4, 14'h3ff9};
assign coe_ary[7'd035] = {14'h26  , 14'h3f49, 14'h21f , 14'h3a87, 14'h1b6d, 14'h8b7 , 14'h3dc6, 14'h8f  , 14'h3ff1, 14'h3ffa};
assign coe_ary[7'd036] = {14'h25  , 14'h3f4a, 14'h21f , 14'h3a7f, 14'h1b2f, 14'h90f , 14'h3dac, 14'h99  , 14'h3fee, 14'h3ffa};
assign coe_ary[7'd037] = {14'h24  , 14'h3f4c, 14'h21f , 14'h3a79, 14'h1aef, 14'h967 , 14'h3d92, 14'ha3  , 14'h3feb, 14'h3ffa};
assign coe_ary[7'd038] = {14'h23  , 14'h3f4d, 14'h21f , 14'h3a74, 14'h1aae, 14'h9bf , 14'h3d78, 14'had  , 14'h3fe8, 14'h3ffb};
assign coe_ary[7'd039] = {14'h22  , 14'h3f4f, 14'h21e , 14'h3a70, 14'h1a6b, 14'ha18 , 14'h3d5e, 14'hb7  , 14'h3fe5, 14'h3ffb};
assign coe_ary[7'd040] = {14'h22  , 14'h3f51, 14'h21c , 14'h3a6d, 14'h1a27, 14'ha71 , 14'h3d44, 14'hc1  , 14'h3fe2, 14'h3ffc};
assign coe_ary[7'd041] = {14'h21  , 14'h3f53, 14'h21b , 14'h3a6b, 14'h19e2, 14'hacb , 14'h3d2b, 14'hcb  , 14'h3fdf, 14'h3ffc};
assign coe_ary[7'd042] = {14'h20  , 14'h3f55, 14'h219 , 14'h3a6a, 14'h199c, 14'hb25 , 14'h3d11, 14'hd5  , 14'h3fdc, 14'h3ffd};
assign coe_ary[7'd043] = {14'h1f  , 14'h3f57, 14'h216 , 14'h3a6a, 14'h1954, 14'hb80 , 14'h3cf8, 14'hdf  , 14'h3fd9, 14'h3ffd};
assign coe_ary[7'd044] = {14'h1e  , 14'h3f59, 14'h213 , 14'h3a6b, 14'h190c, 14'hbda , 14'h3cdf, 14'he9  , 14'h3fd5, 14'h3ffe};
assign coe_ary[7'd045] = {14'h1d  , 14'h3f5c, 14'h210 , 14'h3a6e, 14'h18c2, 14'hc35 , 14'h3cc6, 14'hf3  , 14'h3fd2, 14'h3ffe};
assign coe_ary[7'd046] = {14'h1c  , 14'h3f5e, 14'h20d , 14'h3a71, 14'h1877, 14'hc90 , 14'h3cad, 14'hfd  , 14'h3fcf, 14'h3fff};
assign coe_ary[7'd047] = {14'h1b  , 14'h3f60, 14'h209 , 14'h3a75, 14'h182b, 14'hcec , 14'h3c94, 14'h107 , 14'h3fcc, 14'h3fff};
assign coe_ary[7'd048] = {14'h1a  , 14'h3f63, 14'h205 , 14'h3a7a, 14'h17de, 14'hd47 , 14'h3c7c, 14'h111 , 14'h3fc8, 14'h0   };
assign coe_ary[7'd049] = {14'h19  , 14'h3f66, 14'h200 , 14'h3a80, 14'h1790, 14'hda3 , 14'h3c64, 14'h11b , 14'h3fc5, 14'h0   };
assign coe_ary[7'd050] = {14'h18  , 14'h3f68, 14'h1fb , 14'h3a87, 14'h1741, 14'hdfe , 14'h3c4c, 14'h125 , 14'h3fc1, 14'h1   };
assign coe_ary[7'd051] = {14'h17  , 14'h3f6b, 14'h1f6 , 14'h3a8f, 14'h16f1, 14'he5a , 14'h3c35, 14'h12f , 14'h3fbe, 14'h2   };
assign coe_ary[7'd052] = {14'h16  , 14'h3f6e, 14'h1f1 , 14'h3a97, 14'h16a0, 14'heb6 , 14'h3c1d, 14'h139 , 14'h3fbb, 14'h2   };
assign coe_ary[7'd053] = {14'h15  , 14'h3f71, 14'h1eb , 14'h3aa1, 14'h164e, 14'hf12 , 14'h3c07, 14'h142 , 14'h3fb7, 14'h3   };
assign coe_ary[7'd054] = {14'h14  , 14'h3f74, 14'h1e5 , 14'h3aab, 14'h15fc, 14'hf6d , 14'h3bf0, 14'h14c , 14'h3fb4, 14'h4   };
assign coe_ary[7'd055] = {14'h13  , 14'h3f77, 14'h1df , 14'h3ab6, 14'h15a8, 14'hfc9 , 14'h3bda, 14'h155 , 14'h3fb0, 14'h5   };
assign coe_ary[7'd056] = {14'h12  , 14'h3f7a, 14'h1d9 , 14'h3ac2, 14'h1554, 14'h1024, 14'h3bc5, 14'h15f , 14'h3fad, 14'h5   };
assign coe_ary[7'd057] = {14'h11  , 14'h3f7d, 14'h1d2 , 14'h3acf, 14'h14ff, 14'h107f, 14'h3baf, 14'h168 , 14'h3fa9, 14'h6   };
assign coe_ary[7'd058] = {14'h10  , 14'h3f81, 14'h1cb , 14'h3adc, 14'h14aa, 14'h10da, 14'h3b9b, 14'h171 , 14'h3fa6, 14'h7   };
assign coe_ary[7'd059] = {14'hf   , 14'h3f84, 14'h1c4 , 14'h3aea, 14'h1454, 14'h1135, 14'h3b87, 14'h17a , 14'h3fa2, 14'h8   };
assign coe_ary[7'd060] = {14'hf   , 14'h3f87, 14'h1bc , 14'h3af9, 14'h13fd, 14'h118f, 14'h3b73, 14'h183 , 14'h3f9f, 14'h8   };
assign coe_ary[7'd061] = {14'he   , 14'h3f8a, 14'h1b5 , 14'h3b09, 14'h13a6, 14'h11e9, 14'h3b60, 14'h18c , 14'h3f9b, 14'h9   };
assign coe_ary[7'd062] = {14'hd   , 14'h3f8e, 14'h1ad , 14'h3b19, 14'h134e, 14'h1243, 14'h3b4d, 14'h194 , 14'h3f98, 14'ha   };
assign coe_ary[7'd063] = {14'hc   , 14'h3f91, 14'h1a5 , 14'h3b2a, 14'h12f5, 14'h129c, 14'h3b3b, 14'h19d , 14'h3f95, 14'hb   };
assign coe_ary[7'd064] = {14'hb   , 14'h3f95, 14'h19d , 14'h3b3b, 14'h129c, 14'h12f5, 14'h3b2a, 14'h1a5 , 14'h3f91, 14'hc   };
assign coe_ary[7'd065] = {14'ha   , 14'h3f98, 14'h194 , 14'h3b4d, 14'h1243, 14'h134e, 14'h3b19, 14'h1ad , 14'h3f8e, 14'hd   };
assign coe_ary[7'd066] = {14'h9   , 14'h3f9b, 14'h18c , 14'h3b60, 14'h11e9, 14'h13a6, 14'h3b09, 14'h1b5 , 14'h3f8a, 14'he   };
assign coe_ary[7'd067] = {14'h8   , 14'h3f9f, 14'h183 , 14'h3b73, 14'h118f, 14'h13fd, 14'h3af9, 14'h1bc , 14'h3f87, 14'hf   };
assign coe_ary[7'd068] = {14'h8   , 14'h3fa2, 14'h17a , 14'h3b87, 14'h1135, 14'h1454, 14'h3aea, 14'h1c4 , 14'h3f84, 14'hf   };
assign coe_ary[7'd069] = {14'h7   , 14'h3fa6, 14'h171 , 14'h3b9b, 14'h10da, 14'h14aa, 14'h3adc, 14'h1cb , 14'h3f81, 14'h10  };
assign coe_ary[7'd070] = {14'h6   , 14'h3fa9, 14'h168 , 14'h3baf, 14'h107f, 14'h14ff, 14'h3acf, 14'h1d2 , 14'h3f7d, 14'h11  };
assign coe_ary[7'd071] = {14'h5   , 14'h3fad, 14'h15f , 14'h3bc5, 14'h1024, 14'h1554, 14'h3ac2, 14'h1d9 , 14'h3f7a, 14'h12  };
assign coe_ary[7'd072] = {14'h5   , 14'h3fb0, 14'h155 , 14'h3bda, 14'hfc9 , 14'h15a8, 14'h3ab6, 14'h1df , 14'h3f77, 14'h13  };
assign coe_ary[7'd073] = {14'h4   , 14'h3fb4, 14'h14c , 14'h3bf0, 14'hf6d , 14'h15fc, 14'h3aab, 14'h1e5 , 14'h3f74, 14'h14  };
assign coe_ary[7'd074] = {14'h3   , 14'h3fb7, 14'h142 , 14'h3c07, 14'hf12 , 14'h164e, 14'h3aa1, 14'h1eb , 14'h3f71, 14'h15  };
assign coe_ary[7'd075] = {14'h2   , 14'h3fbb, 14'h139 , 14'h3c1d, 14'heb6 , 14'h16a0, 14'h3a97, 14'h1f1 , 14'h3f6e, 14'h16  };
assign coe_ary[7'd076] = {14'h2   , 14'h3fbe, 14'h12f , 14'h3c35, 14'he5a , 14'h16f1, 14'h3a8f, 14'h1f6 , 14'h3f6b, 14'h17  };
assign coe_ary[7'd077] = {14'h1   , 14'h3fc1, 14'h125 , 14'h3c4c, 14'hdfe , 14'h1741, 14'h3a87, 14'h1fb , 14'h3f68, 14'h18  };
assign coe_ary[7'd078] = {14'h0   , 14'h3fc5, 14'h11b , 14'h3c64, 14'hda3 , 14'h1790, 14'h3a80, 14'h200 , 14'h3f66, 14'h19  };
assign coe_ary[7'd079] = {14'h0   , 14'h3fc8, 14'h111 , 14'h3c7c, 14'hd47 , 14'h17de, 14'h3a7a, 14'h205 , 14'h3f63, 14'h1a  };
assign coe_ary[7'd080] = {14'h3fff, 14'h3fcc, 14'h107 , 14'h3c94, 14'hcec , 14'h182b, 14'h3a75, 14'h209 , 14'h3f60, 14'h1b  };
assign coe_ary[7'd081] = {14'h3fff, 14'h3fcf, 14'hfd  , 14'h3cad, 14'hc90 , 14'h1877, 14'h3a71, 14'h20d , 14'h3f5e, 14'h1c  };
assign coe_ary[7'd082] = {14'h3ffe, 14'h3fd2, 14'hf3  , 14'h3cc6, 14'hc35 , 14'h18c2, 14'h3a6e, 14'h210 , 14'h3f5c, 14'h1d  };
assign coe_ary[7'd083] = {14'h3ffe, 14'h3fd5, 14'he9  , 14'h3cdf, 14'hbda , 14'h190c, 14'h3a6b, 14'h213 , 14'h3f59, 14'h1e  };
assign coe_ary[7'd084] = {14'h3ffd, 14'h3fd9, 14'hdf  , 14'h3cf8, 14'hb80 , 14'h1954, 14'h3a6a, 14'h216 , 14'h3f57, 14'h1f  };
assign coe_ary[7'd085] = {14'h3ffd, 14'h3fdc, 14'hd5  , 14'h3d11, 14'hb25 , 14'h199c, 14'h3a6a, 14'h219 , 14'h3f55, 14'h20  };
assign coe_ary[7'd086] = {14'h3ffc, 14'h3fdf, 14'hcb  , 14'h3d2b, 14'hacb , 14'h19e2, 14'h3a6b, 14'h21b , 14'h3f53, 14'h21  };
assign coe_ary[7'd087] = {14'h3ffc, 14'h3fe2, 14'hc1  , 14'h3d44, 14'ha71 , 14'h1a27, 14'h3a6d, 14'h21c , 14'h3f51, 14'h22  };
assign coe_ary[7'd088] = {14'h3ffb, 14'h3fe5, 14'hb7  , 14'h3d5e, 14'ha18 , 14'h1a6b, 14'h3a70, 14'h21e , 14'h3f4f, 14'h22  };
assign coe_ary[7'd089] = {14'h3ffb, 14'h3fe8, 14'had  , 14'h3d78, 14'h9bf , 14'h1aae, 14'h3a74, 14'h21f , 14'h3f4d, 14'h23  };
assign coe_ary[7'd090] = {14'h3ffa, 14'h3feb, 14'ha3  , 14'h3d92, 14'h967 , 14'h1aef, 14'h3a79, 14'h21f , 14'h3f4c, 14'h24  };
assign coe_ary[7'd091] = {14'h3ffa, 14'h3fee, 14'h99  , 14'h3dac, 14'h90f , 14'h1b2f, 14'h3a7f, 14'h21f , 14'h3f4a, 14'h25  };
assign coe_ary[7'd092] = {14'h3ffa, 14'h3ff1, 14'h8f  , 14'h3dc6, 14'h8b7 , 14'h1b6d, 14'h3a87, 14'h21f , 14'h3f49, 14'h26  };
assign coe_ary[7'd093] = {14'h3ff9, 14'h3ff4, 14'h86  , 14'h3de0, 14'h860 , 14'h1bab, 14'h3a8f, 14'h21e , 14'h3f48, 14'h27  };
assign coe_ary[7'd094] = {14'h3ff9, 14'h3ff7, 14'h7c  , 14'h3dfa, 14'h80a , 14'h1be6, 14'h3a99, 14'h21d , 14'h3f47, 14'h28  };
assign coe_ary[7'd095] = {14'h3ff9, 14'h3ff9, 14'h72  , 14'h3e14, 14'h7b4 , 14'h1c21, 14'h3aa4, 14'h21c , 14'h3f46, 14'h28  };
assign coe_ary[7'd096] = {14'h3ff8, 14'h3ffc, 14'h69  , 14'h3e2d, 14'h75f , 14'h1c59, 14'h3ab0, 14'h21a , 14'h3f45, 14'h29  };
assign coe_ary[7'd097] = {14'h3ff8, 14'h3ffe, 14'h5f  , 14'h3e47, 14'h70a , 14'h1c91, 14'h3abd, 14'h217 , 14'h3f44, 14'h2a  };
assign coe_ary[7'd098] = {14'h3ff8, 14'h1   , 14'h56  , 14'h3e61, 14'h6b6 , 14'h1cc6, 14'h3acc, 14'h215 , 14'h3f44, 14'h2b  };
assign coe_ary[7'd099] = {14'h3ff8, 14'h4   , 14'h4d  , 14'h3e7b, 14'h663 , 14'h1cfa, 14'h3adb, 14'h211 , 14'h3f43, 14'h2b  };
assign coe_ary[7'd100] = {14'h3ff7, 14'h6   , 14'h43  , 14'h3e94, 14'h611 , 14'h1d2d, 14'h3aec, 14'h20e , 14'h3f43, 14'h2c  };
assign coe_ary[7'd101] = {14'h3ff7, 14'h8   , 14'h3a  , 14'h3ead, 14'h5bf , 14'h1d5e, 14'h3afe, 14'h209 , 14'h3f43, 14'h2d  };
assign coe_ary[7'd102] = {14'h3ff7, 14'hb   , 14'h31  , 14'h3ec7, 14'h56e , 14'h1d8d, 14'h3b11, 14'h205 , 14'h3f43, 14'h2d  };
assign coe_ary[7'd103] = {14'h3ff7, 14'hd   , 14'h28  , 14'h3ee0, 14'h51e , 14'h1dbb, 14'h3b26, 14'h200 , 14'h3f43, 14'h2e  };
assign coe_ary[7'd104] = {14'h3ff7, 14'hf   , 14'h20  , 14'h3ef9, 14'h4cf , 14'h1de7, 14'h3b3c, 14'h1fa , 14'h3f43, 14'h2e  };
assign coe_ary[7'd105] = {14'h3ff7, 14'h11  , 14'h17  , 14'h3f11, 14'h481 , 14'h1e12, 14'h3b53, 14'h1f4 , 14'h3f44, 14'h2f  };
assign coe_ary[7'd106] = {14'h3ff6, 14'h13  , 14'hf   , 14'h3f2a, 14'h434 , 14'h1e3a, 14'h3b6b, 14'h1ed , 14'h3f45, 14'h2f  };
assign coe_ary[7'd107] = {14'h3ff6, 14'h15  , 14'h6   , 14'h3f42, 14'h3e7 , 14'h1e61, 14'h3b85, 14'h1e6 , 14'h3f46, 14'h30  };
assign coe_ary[7'd108] = {14'h3ff6, 14'h17  , 14'h3ffe, 14'h3f5a, 14'h39c , 14'h1e86, 14'h3ba0, 14'h1df , 14'h3f47, 14'h30  };
assign coe_ary[7'd109] = {14'h3ff6, 14'h19  , 14'h3ff6, 14'h3f72, 14'h351 , 14'h1eaa, 14'h3bbc, 14'h1d7 , 14'h3f48, 14'h31  };
assign coe_ary[7'd110] = {14'h3ff6, 14'h1b  , 14'h3fee, 14'h3f89, 14'h307 , 14'h1ecc, 14'h3bda, 14'h1cf , 14'h3f49, 14'h31  };
assign coe_ary[7'd111] = {14'h3ff6, 14'h1c  , 14'h3fe6, 14'h3fa1, 14'h2bf , 14'h1eec, 14'h3bf9, 14'h1c6 , 14'h3f4b, 14'h31  };
assign coe_ary[7'd112] = {14'h3ff6, 14'h1e  , 14'h3fdf, 14'h3fb8, 14'h277 , 14'h1f0a, 14'h3c19, 14'h1bc , 14'h3f4d, 14'h32  };
assign coe_ary[7'd113] = {14'h3ff6, 14'h20  , 14'h3fd7, 14'h3fce, 14'h231 , 14'h1f26, 14'h3c3a, 14'h1b2 , 14'h3f4e, 14'h32  };
assign coe_ary[7'd114] = {14'h3ff6, 14'h21  , 14'h3fd0, 14'h3fe4, 14'h1eb , 14'h1f40, 14'h3c5d, 14'h1a8 , 14'h3f51, 14'h32  };
assign coe_ary[7'd115] = {14'h3ff6, 14'h23  , 14'h3fc9, 14'h3ffa, 14'h1a7 , 14'h1f59, 14'h3c81, 14'h19d , 14'h3f53, 14'h32  };
assign coe_ary[7'd116] = {14'h3ff6, 14'h24  , 14'h3fc2, 14'h10  , 14'h164 , 14'h1f70, 14'h3ca7, 14'h192 , 14'h3f55, 14'h32  };
assign coe_ary[7'd117] = {14'h3ff6, 14'h25  , 14'h3fbb, 14'h25  , 14'h122 , 14'h1f85, 14'h3ccd, 14'h186 , 14'h3f58, 14'h32  };
assign coe_ary[7'd118] = {14'h3ff6, 14'h27  , 14'h3fb5, 14'h3a  , 14'he1  , 14'h1f98, 14'h3cf5, 14'h17a , 14'h3f5b, 14'h32  };
assign coe_ary[7'd119] = {14'h3ff6, 14'h28  , 14'h3fae, 14'h4f  , 14'ha1  , 14'h1fa9, 14'h3d1f, 14'h16d , 14'h3f5e, 14'h32  };
assign coe_ary[7'd120] = {14'h3ff6, 14'h29  , 14'h3fa8, 14'h63  , 14'h62  , 14'h1fb8, 14'h3d49, 14'h160 , 14'h3f61, 14'h32  };
assign coe_ary[7'd121] = {14'h3ff7, 14'h2a  , 14'h3fa2, 14'h77  , 14'h25  , 14'h1fc6, 14'h3d75, 14'h152 , 14'h3f64, 14'h32  };
assign coe_ary[7'd122] = {14'h3ff7, 14'h2b  , 14'h3f9c, 14'h8a  , 14'h3fe8, 14'h1fd1, 14'h3da2, 14'h144 , 14'h3f68, 14'h31  };
assign coe_ary[7'd123] = {14'h3ff7, 14'h2c  , 14'h3f97, 14'h9d  , 14'h3fad, 14'h1fdb, 14'h3dd1, 14'h135 , 14'h3f6c, 14'h31  };
assign coe_ary[7'd124] = {14'h3ff7, 14'h2d  , 14'h3f91, 14'hb0  , 14'h3f73, 14'h1fe2, 14'h3e01, 14'h126 , 14'h3f70, 14'h31  };
assign coe_ary[7'd125] = {14'h3ff7, 14'h2d  , 14'h3f8c, 14'hc2  , 14'h3f3b, 14'h1fe8, 14'h3e32, 14'h117 , 14'h3f74, 14'h30  };
assign coe_ary[7'd126] = {14'h3ff7, 14'h2e  , 14'h3f87, 14'hd4  , 14'h3f03, 14'h1fec, 14'h3e64, 14'h107 , 14'h3f78, 14'h30  };
assign coe_ary[7'd127] = {14'h3ff7, 14'h2f  , 14'h3f82, 14'he5  , 14'h3ecd, 14'h1fee, 14'h3e98, 14'hf6  , 14'h3f7d, 14'h2f  };

endmodule

